package main

import (
	"context"
	global "developer_tools/globals"
	"developer_tools/internal"
	"developer_tools/internal/command"
	"time"

	"github.com/wailsapp/wails/v2/pkg/runtime"
	"golang.org/x/crypto/ssh"
)

// App struct
type App struct {
	ctx            context.Context
	sshClient      *ssh.Client
	isConnected    bool
	currentSession *ssh.Session
	supportStream  bool
}

// NewApp creates a new App application struct
func NewApp() *App {
	return &App{}
}

// startup is called when the app starts. The context is saved
// so we can call the runtime methods
func (a *App) startup(ctx context.Context) {
	a.ctx = ctx
}

func (a *App) shutdown(ctx context.Context) {
	log_.Info("[App]Shutting down...")
	// 在这里执行关闭 SSH 连接的逻辑
	if a.isConnected && a.sshClient != nil {
		a.sshClient.Close()
		a.isConnected = false
		a.sshClient = nil
		log_.Info("SSH connection closed")
	}
	// 关闭所有事件监听器
	runtime.EventsOffAll(ctx)
}

// ConnectSSH
func (a *App) ConnectSSH(username, password, host string, port int, store bool) error {
	if a.isConnected {
		log_.Debugf("SSH connection status: %v", a.isConnected)
		return nil // 如果已经连接，直接返回
	}
	client, err := ConnectSsh(a.ctx, username, password, host, port)
	if err != nil {
		return err
	}

	a.sshClient = client
	a.isConnected = true

	// 保存连接信息
	if store {
		SaveConnectedSSHHost(username, password, host, port)
		log_.Debug("Connected SSH host saved")
	}

	return nil
}

// DisconnectSSH 断开 SSH 连接
func (a *App) DisconnectSSH() {
	if a.isConnected && a.sshClient != nil {
		a.sshClient.Close()
		a.isConnected = false
		a.sshClient = nil
		a.currentSession = nil
		a.supportStream = false
		log_.Info("SSH connection closed")
	}
}

// StartLogStream
func (a *App) StartLogStream(cmd string, supportStream bool) {
	if !a.isConnected {
		runtime.EventsEmit(a.ctx, "error", global.SSHSessionNotConnected)
		return // 如果未连接，直接返回
	}

	a.supportStream = supportStream
	DoShell(a, a.sshClient, cmd, supportStream)
}

// 停止日志流
func (a *App) StopLogStream() {
	switch global.CurrentOS {
	case "windows":
		StopLogStreamWin(a)
	default:
		StopLogStreamUnix(a.ctx)
	}
}

// 获取已经连接的SSH服务器信息
func (a *App) GetConnectedSSHHost() []string {
	return GetHostList()
}

// 获取指定SSH服务器信息
func (a *App) GetHostInfo(host string, port int) map[string]any {
	info := GetHostInfo(host, port)
	if info.Host == "" {
		return map[string]any{}
	}

	return map[string]any{
		"host":     info.Host,
		"port":     info.Port,
		"username": info.Username,
		"password": info.Password,
	}
}

func (a *App) CheckCmdIsContinuous(cmd string) bool {
	return command.CheckCmdIsContinuous(cmd)
}

// DeleteSSHHost 删除存储的SSH服务器信息
func (a *App) DeleteSSHHost(host string, port int) []string {
	e := DeleteSSHHost(host, port)
	if e != nil {
		runtime.EventsEmit(a.ctx, "error", global.SSHConfigDeleteError)
		return []string{}
	} else {
		return GetHostList()
	}
}

// CheckAllSSHAlive checks the connectivity status of multiple SSH hosts
// and returns a map indicating which hosts are alive or not
// The input is a slice of host addresses, and the return value is a map
// where the keys are host addresses and the values are boolean connectivity statuses
func (a *App) CheckAllSSHAlive(hostPorts []string) map[string]bool {
	result := make(map[string]bool)

	// Initialize all hosts with default false value
	for _, hostPort := range hostPorts {
		result[hostPort] = false
	}

	// Create a channel to receive results
	resultChan := make(chan struct {
		hostPort string
		isAlive  bool
	}, len(hostPorts))

	// Launch goroutines for each host check
	for _, hostPort := range hostPorts {
		go func(hp string) {
			host, port, err := internal.ParseHostPort(hp)
			if err != nil {
				log_.Errorf("Invalid host:port format: %s", hp)
				return
			}

			// Send result to channel
			resultChan <- struct {
				hostPort string
				isAlive  bool
			}{
				hostPort: hp,
				isAlive:  CheckSSHAlive(host, port),
			}
		}(hostPort)
	}

	// Collect results from channel
	for range hostPorts {
		select {
		case res := <-resultChan:
			result[res.hostPort] = res.isAlive
		case <-time.After(5 * time.Second): // Add timeout to prevent blocking forever
			log_.Warn("Timeout waiting for SSH check results")
			continue
		}
	}

	return result
}
